package erfgame.frontend.desktop.view.terrain.iso.handler;

import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.logging.Logger;

import erfgame.core.Point3D;
import erfgame.core.dao.ObjectDAO;
import erfgame.core.memory.Pointer;
import erfgame.core.world.World;
import erfgame.core.world.WorldDAOManager;
import erfgame.core.world.terrain.AbstractVoxelColorPicker;
import erfgame.core.world.terrain.HorizontalAngleVoxelColorPicker;
import erfgame.core.world.terrain.RotatedVoxelColorPicker;
import erfgame.core.world.terrain.TerrainColorSource;
import erfgame.core.world.terrain.TerrainColorSourceIndexFactory;
import erfgame.core.world.terrain.VerticalLightAngleVoxelColorPicker;
import erfgame.core.world.terrain.TerrainConstants;

import erfgame.frontend.desktop.view.terrain.iso.IsometricTerrainView;

public class VoxelColorDetailsInteractionHandler extends BaseClickInteractionHandler {

	private static final Logger log = Logger.getLogger( VoxelColorDetailsInteractionHandler.class.getName() );
	
	private IsometricTerrainView view;
	private WorldDAOManager daoManager;
	private TerrainColorSourceIndexFactory colorSourceIndexFactory;
	
	public VoxelColorDetailsInteractionHandler( IsometricTerrainView view, WorldDAOManager daoManager, TerrainColorSourceIndexFactory colorSourceIndexFactory ) {
		super( MouseEvent.BUTTON1 );
		this.view = view;
		this.daoManager = daoManager;
		this.colorSourceIndexFactory = colorSourceIndexFactory;
	}
	

	
	@Override
	protected boolean handleClick(MouseEvent e) {
		Point3D p = new Point3D();
		
		p = view.getTerrainPosition(e.getX(), e.getY(), p);
		if( p != null ) {
			World world = view.getCurrentWorld();
			int blockWidth = world.getBlockWidth();
			int blockHeight = world.getBlockHeight();
			int blockDepth = world.getBlockDepth();
			
			int blocksX = world.getBlocksX();
			int blocksY = world.getBlocksY();
			int blocksZ = world.getBlocksZ();
			AbstractVoxelColorPicker colorPicker = new HorizontalAngleVoxelColorPicker(
					-Math.PI/8,
					0, 
					16, 
					null, 
					blockWidth, 
					blockHeight,
					blockDepth, 
					false
			);
			// look up terrain
			int tx = p.x / blockWidth;
			int ty = p.y / blockHeight;
			int tz = p.z / blockDepth;
			
			ObjectDAO<Point3D, Pointer<byte[][][]>> terrainDAO = daoManager.getBlockTerrainDAO(world);

			ArrayList<Pointer<byte[][][]>> pointers = new ArrayList<Pointer<byte[][][]>>(9);
			byte[][][][][][] terrain = new byte[3][3][3][][][];
			for( int dx=-1; dx<=1; dx++) {
				for( int dy=-1; dy<=1; dy++) {
					for( int dz=-1; dz<=1; dz++ ) {
						int x = tx + dx;
						int y = ty + dy;
						int z = tz + dz;
						if( x >= 0 && y >= 0 && z >= 0 && x < blocksX && y < blocksY && z < blocksZ ) {
							Point3D key = new Point3D( x, y, z );
							Pointer<byte[][][]> terrainBlock = terrainDAO.retrieveObject(key);
							terrain[dx+1][dy+1][dz+1] = terrainBlock.getValue();
							pointers.add( terrainBlock );
						}
					}
				}
			}
			
			int lx = p.x - tx * blockWidth;
			int ly = p.y - ty * blockHeight;
			int lz = p.z - tz * blockDepth;
			
			byte terrainType = terrain[1][1][1][lx][ly][lz];
			// TODO : check that ly+1 isn't actually solid (and blocking us)
			if( ly < blockHeight ) {
				byte tt = terrain[1][1][1][lx][ly+1][lz];
				if( tt != TerrainConstants.TERRAIN_TYPE_AIR ) {
					ly++;
					terrainType = tt;					
				}
			} else {
				// otherwise just ignore it and hope for the best
				log.warning("may have wrong voxel");
			}
			
			TerrainColorSource colorSource = colorSourceIndexFactory.createIndex(world).getTerrainColorSource(terrainType);
			
			int color = colorPicker.getColor(
					colorSource, 
					1, 1, 1, 
					terrain, 
					lx, ly, lz, 
					-1, 
					p.x, p.y, p.x, 
					tz==0
			);			
			// TODO : show color?
			log.info("Color: "+Integer.toHexString(color));
//			colorPicker.getColor(
//					colorSource, 
//					1, 1, 1, 
//					terrain, 
//					lx, ly, lz, 
//					0, 
//					p.x, p.y, p.x, 
//					tz==0
//			);			
			
			for( int i=pointers.size(); i>0; ) {
				i--;
				pointers.get( i ).free();
			}
		}
		return true;
	}

}
